#include "ReaderStatusProc.h"
#include <cstdlib>
#include <cassert>

#define TAILLE 128 * 1024
#define NB_BLOCS 50000

void* ptrs  [NB_BLOCS];
int   lifes [NB_BLOCS];
int   start [NB_BLOCS];
bool  freed [NB_BLOCS];
bool  allocated[NB_BLOCS];


void pattern_lineaire(){
  printf("[Pattern avec blocs simultanés et iso durée de vie]\n");
  for(int i=0;i<NB_BLOCS;i++){
    //iso durée de vie
    lifes[i]=10;
    //naissances simultanées
    start[i]=0;
  }
}


void pattern_modulo10(int periode){
  printf("[Pattern avec blocs simultanés et durée de vie répartie modulo 10]\n");
  for(int i=0;i<NB_BLOCS;i++){
    
    //duree de vie des objets dépend de leur index
    lifes[i]=(i%periode);
    
    //naissances successives
    start[i]=i;
    
  }
}

void pattern_alterne(){
  printf("[Pattern avec blocs simultanés et iso durée de vie repartie en deux classes de durée de vie]\n");
  for(int i=0;i<NB_BLOCS;i++){
    //grosse durée de vie et petite durée de vie alterné dans les objets
    if(i%2==0)
      lifes[i]=NB_BLOCS/2;
    else
      lifes[i]=10;
    
    //naissance successives
    start[i]=i;
  }
}

void pattern_alterne_3(){
  printf("[Pattern avec blocs simultanés durée de vie répartie par tranche de trois]\n");
  for(int i=0;i<NB_BLOCS;i++){
    if(i%3==0){
      lifes[i]=10;
    }
    if(i%3==1){
      lifes[i]=1000;
    }
    if(i%3==2){
      lifes[i]=NB_BLOCS/2;
    }
    start[i]=i;
  }
}


void pattern_alterne_4(){
  
  printf("[Pattern avec blocs simultanés et durée de vie répartie par tranche de quatre]\n");
  for(int i=0;i<NB_BLOCS;i++){
    if(i%4==0){
      lifes[i]=10;
    }
    if(i%4==1){
      lifes[i]=1000;
    }
    if(i%4==2){
      lifes[i]=NB_BLOCS/3;
    }
    if(i%4==3){
      lifes[i]=NB_BLOCS/2;
    }
    start[i]=i;
  }
}


void pattern_court_long(){
  printf("[Pattern avec blocs simultanés et repartition court long]\n");
  for(int i=0;i<NB_BLOCS/2;i++){
    lifes[i]=NB_BLOCS/6;//une valeur au hasard entre 1 et 10
    start[i]=i;
  }
  for(int i=NB_BLOCS/2;i<NB_BLOCS;i++){
    lifes[i]=NB_BLOCS/2;//une valeur au hasard entre 1 et 10
    start[i]=i;
  }
}

int freed_blocs=0;
void free_dead_bloc(int current_time){
  for(int i=0;i<NB_BLOCS;i++){
    if((start[i]+lifes[i])==current_time){
      
      //printf("candidat is %d=>%d ; blocs=%p\n",i,lifes[i],ptrs[i]);
      //sleep(1);
      if(allocated[i] && !freed[i]){
	freed_blocs++;
	free(ptrs[i]);
	freed[i]=true;
	
      }
   }
  }
}

int allocated_blocs=0;
void allocate_bloc(int current_time){
  //sleep(1);
  //printf("---step:[%d]---\n",current_time);
  for(int i=0;i<NB_BLOCS;i++){
      if(start[i]==current_time){
	ptrs[i]=malloc(TAILLE);
	assert(ptrs[i]!=NULL);
	allocated_blocs++;
	allocated[i]=true;
      }
  }
} 



bool bloc_vivant()
{
  
  for(int i=0;i<NB_BLOCS;i++)
    {
      if(!freed[i])
	return true;
    }
  return false;
}

int main(void){
  int compteur =0;
  status_t st;
  ReaderStatusProc::getSelfStatus(st);
  ReaderStatusProc::printStatus(st,"a.out",1024,"Mo");
  
  for(int j=0;j<NB_BLOCS;j++){
    freed[j]=false;
    allocated[j]=false;
  }
  
#ifdef PATTERN_LINEAIRE
  pattern_lineaire();
#endif
  
#ifdef PATTERN_MODULO_10
  pattern_modulo10(10);
#endif
  
#ifdef PATTERN_MODULO_20
  pattern_modulo10(20);
#endif
  
#ifdef PATTERN_MODULO_100
  pattern_modulo10(100);
#endif
  
#ifdef PATTERN_ALTERNE
  pattern_alterne();
#endif
  
#ifdef PATTERN_ALTERNE_3
  pattern_alterne_3();
#endif
  
#ifdef PATTERN_ALTERNE_4
  pattern_alterne_4();
#endif
  
#ifdef PATTERN_COURT_LONG
  pattern_court_long();
#endif
  

  //int instant=0;
  //while(bloc_vivant()){
  //i sert d'horloge globale
  for(int instant=0;bloc_vivant();instant++){
    
    //allouer les blocs naissant à l'instant
    //printf("lifes[%d]=%d\n",instant,lifes[instant]);
    
    //allouer les blocs naissant à l'instant
    allocate_bloc(instant);
    
    //liberer les blocs mourrant à l'instant
    free_dead_bloc(instant);
  }  
    //}
  
  
  printf("allocated blocs:%d freed blocs:%d\n",allocated_blocs,freed_blocs);
  
  assert(allocated_blocs==NB_BLOCS && freed_blocs==NB_BLOCS);
  
  ReaderStatusProc::getSelfStatus(st);
  ReaderStatusProc::printStatus(st,"a.out",1024,"Mo");
  
  return 0;
}

